/*
 * 天虹商场股份有限公司版权所有.
 */
package com.rainbow.formework.context;

import com.rainbow.formework.annotation.HMKAutowired;
import com.rainbow.formework.annotation.HMKController;
import com.rainbow.formework.annotation.HMKService;
import com.rainbow.formework.aop.HMKAopConfig;
import com.rainbow.formework.beans.HMKBeanPostProcessor;
import com.rainbow.formework.beans.HMKBeanWrapper;
import com.rainbow.formework.core.GPBeanFactory;
import com.rainbow.formework.beans.HMKBeanDefinition;
import com.rainbow.formework.context.support.HMKBeanDefinitionReader;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * TODO
 *
 * @author 黄明坤
 * @version 1.0.0
 * @date 2020/7/3
 */
public class HMKApplicationContext  extends HMKDefaultListableBeanFactory implements GPBeanFactory {

    private String [] configLocations;

    private HMKBeanDefinitionReader reader;

    //用来保证注册式单例的容器
    private Map<String,Object> beanCacheMap = new HashMap<String, Object>();

    private Map<String, HMKBeanWrapper> beanWrapperMap = new ConcurrentHashMap<String, HMKBeanWrapper>();


    public String[] getBeanDefinitionNames() {
        return this.beanDefinitionMap.keySet().toArray(new String[this.beanDefinitionMap.size()]);
    }


    public HMKApplicationContext(String ... configLocations){
        this.configLocations = configLocations;
        try {
            refresh();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public void refresh() throws Exception {
        //定位
        this.reader = new HMKBeanDefinitionReader(configLocations);

        //加载
        List<String> beanDefinitions = reader.loadBeanDefinitions();

        //注册
        doRegisty(beanDefinitions);


        //依赖注入（lazy-init = false），要是执行依赖注入
        //在这里自动调用getBean方法
        doAutowrited();

//        MyAction myAction = (MyAction)this.getBean("myAction");
//        myAction.query(null,null,"任性的Tom老师");
    }


    /**
     * 依赖注入
     */
    private void doAutowrited() throws Exception {

        for (Map.Entry<String, HMKBeanDefinition> beanDefinitionEntry : this.beanDefinitionMap.entrySet()) {
            String beanName = beanDefinitionEntry.getKey();
            if (!beanDefinitionEntry.getValue().isLazyInit()) {
                Object obj = getBean(beanName);
//                System.out.println(obj.getClass());
            }
        }

        for (Map.Entry<String, HMKBeanWrapper> beanWrapperEntry : beanWrapperMap.entrySet()) {
            //对象的属性注入
            populateBean(beanWrapperEntry.getKey(),beanWrapperEntry.getValue().getOriginalInstance());
        }
    }

    /**
     * 类的属性的注入
     * @param key
     * @param instance
     */
    private void populateBean(String key, Object instance) {
        Class clazz = instance.getClass();

        //不是所有牛奶都叫特仑苏
        if(!(clazz.isAnnotationPresent(HMKController.class) ||
                clazz.isAnnotationPresent(HMKService.class))){
            return;
        }

        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            if (!field.isAnnotationPresent(HMKAutowired.class)){ continue; }

            HMKAutowired autowired = field.getAnnotation(HMKAutowired.class);

            String autowiredBeanName = autowired.value().trim();

            if("".equals(autowiredBeanName)){
                autowiredBeanName = field.getType().getName();
            }

            field.setAccessible(true);

            try {

                //System.out.println("=======================" +instance +"," + autowiredBeanName + "," + this.beanWrapperMap.get(autowiredBeanName));
                field.set(instance,this.beanWrapperMap.get(autowiredBeanName).getWrappedInstance());
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

        }
    }

    private void doRegisty(List<String> beanDefinitions) {


        //beanName有三种情况:
        //1、默认是类名首字母小写
        //2、自定义名字
        //3、接口注入
        try {
            for (String className : beanDefinitions) {

                Class<?> beanClass = Class.forName(className);

                //如果是一个接口，是不能实例化的
                //用它实现类来实例化
                if(beanClass.isInterface()){ continue; }

                HMKBeanDefinition beanDefinition = reader.registerBean(className);
                if(beanDefinition != null){
                    this.beanDefinitionMap.put(beanDefinition.getFactoryBeanName(),beanDefinition);
                }


                Class<?>[] interfaces = beanClass.getInterfaces();
                for (Class<?> i: interfaces) {
                    //如果是多个实现类，只能覆盖
                    //为什么？因为Spring没那么智能，就是这么傻
                    //这个时候，可以自定义名字
                    this.beanDefinitionMap.put(i.getName(),beanDefinition);
                }
                //到这里为止，容器初始化完毕
            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    public Object getBean(String beanName) throws Exception {
        HMKBeanDefinition hmkBeanDefinition = beanDefinitionMap.get(beanName);
        String className = hmkBeanDefinition.getBeanClassName();
        HMKBeanPostProcessor beanPostProcessor = new HMKBeanPostProcessor();
        Object instance = instantionBean(hmkBeanDefinition);
        if(null == instance ){
            return null;
        }
        beanPostProcessor.postProcessAfterInitialization(instance,beanName);

        //将当前反射生成的对象包装起来
        HMKBeanWrapper hmkBeanWrapper = new HMKBeanWrapper(instance);
        hmkBeanWrapper.setAopConfig(instantionAopConfig(hmkBeanDefinition));
        hmkBeanWrapper.setPostProcessor(beanPostProcessor);
        this.beanWrapperMap.put(beanName,hmkBeanWrapper);

        beanPostProcessor.postProcessBeforeInitialization(instance,beanName);
        //返回一个代理类的对象
        return this.beanWrapperMap.get(beanName).getWrappedInstance();
    }

    private HMKAopConfig instantionAopConfig(HMKBeanDefinition hmkBeanDefinition) throws  Exception{
        HMKAopConfig config = new HMKAopConfig();
        String expression = reader.getConfig().getProperty("pointCut");
        String[] before = reader.getConfig().getProperty("aspectBefore").split("\\s");
        String[] after = reader.getConfig().getProperty("aspectAfter").split("\\s");

        String className = hmkBeanDefinition.getBeanClassName();
        Class<?> clazz = Class.forName(className);

        Pattern pattern = Pattern.compile(expression);

        Class aspectClass = Class.forName(before[0]);
        //在这里得到的方法都是原生的方法
        for (Method m : clazz.getMethods()){

            //public .* com\.gupaoedu\.vip\.spring\.demo\.service\..*Service\..*\(.*\)
            //public java.lang.String com.gupaoedu.vip.spring.demo.service.impl.ModifyService.add(java.lang.String,java.lang.String)
            Matcher matcher = pattern.matcher(m.toString());
            if(matcher.matches()){
                //能满足切面规则的类，添加的AOP配置中
                config.put(m,aspectClass.newInstance(),new Method[]{aspectClass.getMethod(before[1]),aspectClass.getMethod(after[1])});
            }
        }



        return  config;
    }

    //传一个BeanDefinition，就返回一个实例Bean
    private Object instantionBean(HMKBeanDefinition hmkBeanDefinition) {
        Object instance = null;

        String className = hmkBeanDefinition.getBeanClassName();
        //因为根据Class才能确定一个类是否有实例
        try {
            if(this.beanCacheMap.containsKey(className)){
                instance = this.beanCacheMap.get(className);
            }else{
                Class<?> clazz = Class.forName(className);
                instance = clazz.newInstance();
                this.beanCacheMap.put(className,instance);
            }
            return instance;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public Properties getConfig(){
        return this.reader.getConfig();
    }
}
